﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data;
using System.Reflection;
using popLib.CustomeControl;
using Microsoft.Reporting.WinForms;
using System.Collections;
using System.Drawing;

namespace popLib.ModelSystem
{
    public partial class Global
    {
        public static void InitListFormButton(Form form, Button btn_select, Button btn_search, Button btn_view, Button btn_new, FormLanguage language = FormLanguage.Vietnamese)
        {
            //not for init second time
            if (form.AccessibleName == form.Name)
                return;

            form.AccessibleName = form.Name; //set this value to flag for preventing form from init second times

            ////form.Icon = ResourceData.logo24;
            btn_select.AutoSize = btn_view.AutoSize = btn_new.AutoSize = btn_search.AutoSize = true;
            ToolTip tooltip = new ToolTip();

            switch (language)
            {
                default:
                case FormLanguage.Vietnamese:
                    btn_select.Text = "&Chọn (F1)";
                    btn_view.Text = "&Xem chi tiết (F2)";
                    btn_new.Text = "Thêm &mới (F3)";
                    btn_search.Text = "&Tìm (F4)";

                    tooltip.SetToolTip(btn_select, "Chọn một danh mục (F1)");
                    tooltip.SetToolTip(btn_view, "Xem chi tiết một danh mục (F2)");
                    tooltip.SetToolTip(btn_new, "Thêm mới danh mục (F3)");
                    tooltip.SetToolTip(btn_search, "Tìm kiếm danh mục(F4)");
                    break;
                case FormLanguage.English:
                case FormLanguage.Custom:
                    btn_select.Text = "S&elect (F1)";
                    btn_view.Text = "&View detail (F2)";
                    btn_new.Text = "Add new (F3)";
                    btn_search.Text = "&Search (F4)";

                    tooltip.SetToolTip(btn_select, "Select one item (F1)");
                    tooltip.SetToolTip(btn_view, "View detail of selected record (F2)");
                    tooltip.SetToolTip(btn_new, "Add new record (F3)");
                    tooltip.SetToolTip(btn_search, "Search with input value(F4)");
                    break;
            }
            

            form.KeyPreview = true;
            form.KeyUp += delegate(object sender, KeyEventArgs e)
            {
                switch (e.KeyCode)
                {
                    case Keys.F1: btn_select.PerformClick(); break;
                    case Keys.F2: btn_view.PerformClick(); break;
                    case Keys.F3: btn_new.PerformClick(); break;
                    case Keys.F4: btn_search.PerformClick(); break;
                }
            };
        }

        public static void InitDetailFormButton(Form form, Button btn_add, Button btn_update, Button btn_confirm, Button btn_dispose, Button btn_cancel, Button btn_save, Button btn_print)
        {
            //not for init second time
            if (form.AccessibleName == form.Name)
                return;

            form.AccessibleName = form.Name; //set this value to flag for preventing form from init second times
            ////form.Icon = ResourceData.logo24;
            form.Tag = true;

            if (btn_print != null)
            {
                btn_print.AutoSize = true;
                btn_print.Text = "&In báo cáo (F7)";
            }

            if (btn_add != null)
            {
                btn_add.AutoSize = true;
                btn_add.Text = "Thêm &mới (F1)";
            }

            if (btn_cancel != null)
            {
                btn_cancel.AutoSize = true;
                btn_cancel.Text = "&Hủy (F5)";
            }

            if (btn_confirm != null)
            {
                btn_confirm.AutoSize = true;
                btn_confirm.Text = "&Xác nhận (F3)";
            }

            if (btn_dispose != null)
            {
                btn_dispose.AutoSize = true;
                btn_dispose.Text = "Hủy C&T (F4)";
            }

            if (btn_save != null)
            {
                btn_save.AutoSize = true;
                btn_save.Text = "&Lưu (F6)";
            }

            if (btn_update != null)
            {
                btn_update.AutoSize = true;
                btn_update.Text = "&Cập nhật (F2)";
            }

            form.KeyPreview = true;
            form.KeyUp += delegate(object sender, KeyEventArgs e)
            {
                switch (e.KeyCode)
                {
                    case Keys.F1: if (btn_add != null) btn_add.PerformClick(); break;
                    case Keys.F2: if (btn_update != null) btn_update.PerformClick(); break;
                    case Keys.F3: if (btn_print != null) btn_confirm.PerformClick(); break;
                    case Keys.F4: if (btn_print != null) btn_dispose.PerformClick(); break;
                    case Keys.F5: if (btn_print != null) btn_cancel.PerformClick(); break;
                    case Keys.F6: if (btn_print != null) btn_save.PerformClick(); break;
                    case Keys.F7: if (btn_print != null) btn_print.PerformClick(); break;
                    case Keys.Escape: form.Close(); break;
                    case Keys.Enter: if (form.Tag != null && (bool)form.Tag == true) WindowLib.PressKey(Keys.Tab); break;
                }
            };
        }

        public static void InitDetailFormButton(Form form, Button btn_add, Button btn_copy, Button btn_update, Button btn_confirm, Button btn_dispose, Button btn_cancel, Button btn_save, Button btn_print)
        {
            //not for init second time
            if (form.AccessibleName == form.Name)
                return;

            form.AccessibleName = form.Name; //set this value to flag for preventing form from init second times
            ////form.Icon = ResourceData.logo24;
            form.Tag = true;

            if (btn_print != null)
            {
                btn_print.AutoSize = true;
                btn_print.Text = "&In báo cáo (F7)";
            }

            if (btn_add != null)
            {
                btn_add.AutoSize = true;
                btn_add.Text = "Thêm &mới (F1)";
            }

            if (btn_cancel != null)
            {
                btn_cancel.AutoSize = true;
                btn_cancel.Text = "&Hủy (F5)";
            }

            if (btn_confirm != null)
            {
                btn_confirm.AutoSize = true;
                btn_confirm.Text = "&Xác nhận (F3)";
            }

            if (btn_dispose != null)
            {
                btn_dispose.AutoSize = true;
                btn_dispose.Text = "Hủy C&T (F4)";
            }

            if (btn_save != null)
            {
                btn_save.AutoSize = true;
                btn_save.Text = "&Lưu (F6)";
            }

            if (btn_update != null)
            {
                btn_update.AutoSize = true;
                btn_update.Text = "&Cập nhật (F2)";
            }

            if (btn_copy != null)
            {
                btn_copy.AutoSize = true;
                btn_copy.Text = "Nhân đôi (F8)";
            }

            form.KeyPreview = true;
            form.KeyUp += delegate(object sender, KeyEventArgs e)
            {
                switch (e.KeyCode)
                {
                    case Keys.F1: if (btn_add != null) btn_add.PerformClick(); break;
                    case Keys.F2: if (btn_update != null) btn_update.PerformClick(); break;
                    case Keys.F3: if (btn_print != null) btn_confirm.PerformClick(); break;
                    case Keys.F4: if (btn_print != null) btn_dispose.PerformClick(); break;
                    case Keys.F5: if (btn_print != null) btn_cancel.PerformClick(); break;
                    case Keys.F6: if (btn_print != null) btn_save.PerformClick(); break;
                    case Keys.F7: if (btn_print != null) btn_print.PerformClick(); break;
                    case Keys.F8: if (btn_copy != null) btn_copy.PerformClick(); break;
                    case Keys.Escape: form.Close(); break;
                    case Keys.Enter: if (form.Tag != null && (bool)form.Tag == true) WindowLib.PressKey(Keys.Tab); break;
                }
            };
        }

        public static void InitTextBoxListUpDown(Control[] controls, DataGridView dgv)
        {
            foreach (var item in controls)
            {
                item.KeyDown += delegate(object sender, KeyEventArgs e)
                {
                    Control control = (Control)sender;
                    switch (e.KeyCode)
                    {
                        case Keys.Up: MoveNextIndex(-1, dgv); break;
                        case Keys.Down: MoveNextIndex(1, dgv); break;
                    }
                };
            }
        }

        private static void MoveNextIndex(int index, DataGridView dgv)
        {
            if (dgv.CurrentRow == null) return;

            int currentIndex = dgv.CurrentRow.Index;
            currentIndex += index;

            if (currentIndex < 0)
            {
                currentIndex = 0;
            }

            if (currentIndex >= dgv.Rows.Count)
            {
                currentIndex = dgv.Rows.Count - 1;
            }

            dgv.ClearSelection();
            //dgv_list.Rows[currentIndex].Selected = true;

            for (int i = 0; i < dgv.Columns.Count; i++)
            {
                if (dgv.Columns[i].Visible)
                {
                    dgv.CurrentCell = dgv.Rows[currentIndex].Cells[i];
                    break;
                }
            }

            
        }

        public enum StatusType { Moi_Huy_XacNhan, Nam_Nu, SuDung_True_False, MaBenhICD10, DungTuyen_TraiTuyen, NhaThuoc, BoPhanBHYT_NT_NG }

        public static void InitStatusCombobox(ComboBox control, StatusType status, bool showSelectAll = true, bool isDropDownList = true, bool suggestMode = false, AutoCompleteMode autoCompleteMode = AutoCompleteMode.SuggestAppend)
        {

            List<ObjectData> data = new List<ObjectData>();

            switch (status)
            {
                case StatusType.Moi_Huy_XacNhan:
                    data = new List<ObjectData>()
                    { 
                        new ObjectData(){ Name = "Mới", ID = "M" },
                        new ObjectData(){ Name = "Xác nhận", ID = "XN" },
                        new ObjectData(){ Name = "Hủy", ID = "H" },
                    };
                    break;
                case StatusType.Nam_Nu:
                    data = new List<ObjectData>()
                    { 
                        new ObjectData(){ Name = "Nam", ID = true },
                        new ObjectData(){ Name = "Nữ", ID = false },
                    };
                    break;
                case StatusType.SuDung_True_False:
                    data = new List<ObjectData>()
                    { 
                        new ObjectData(){ Name = "Sử dụng", ID = true },
                        new ObjectData(){ Name = "Bị khóa", ID = false },
                    };
                    break;
                case StatusType.MaBenhICD10:
                    string dataType = "Bất thường Ebstein,Q22.5,Bệnh cơ tim dãn nở,I42.0,Bệnh cơ tim do rượu,I42.6,Bệnh cơ tim hạn chế,I42.5,Bệnh cơ tim phì đại không tắc nghẽn,I42.2,Bệnh cơ tim phì đại tắc nghẽn,I42.1,Bệnh cơ tim thiếu máu cục bộ,I25.5,Bệnh mạch máu ngoại biên,I73,Bệnh phổi tắc nghẽn mãn tính - COPD,J44,Bệnh thận mãn,N18,Blốc ba nhánh,I45.3,Blốc hai nhánh,I45.2,Blốc nhánh phải ,I45.0,Blốc nhĩ thất độ I ,I44.0,Blốc nhĩ thất độ II ,I44.1,Blốc nhĩ thất độ III ,I44.2,Blốc phân nhánh trái sau,I44.5,Blốc phân nhánh trái trước,I44.4,Block tim bẩm sinh,Q24.6,Bóc tách động mạch chủ,I71.0,Chuyển vị đại động mạch,Q20.3,Cơn đau thắt ngực do co mạch vành,I20.1,Cơn đau thắt ngực không ổn định,I20.0,Còn ống động mạch - PCA,Q25.0,Cửa sổ phế chủ,Q21.4,Cường giáp - BASEDOW,E05,Đái tháo đường type I,E10,Đái tháo đường type II,E11,Dãn tĩnh mạch chi dưới,I83.9,Đảo ngược phủ tạng,Q89.3,Di chứng nhồi máu não,I69.3,Di chứng tai biến mạch máu não (không xác định do xuất huyết hay nhồi máu),I69.4,Di chứng xuất huyết não,I69.1,Dị tật bẩm sinh khác của van 3 lá,Q22.8,Dị tật bẩm sinh khác của van động mạch phổi,Q22.3,Dị tật khác của buồng tim và bộ phận nối kết,Q20.8,Dị tật mạch vành,Q24.5,Hen phế quản,J45,Hẹp động mạch phổi,Q25.6,Hẹp dưới van ĐMC bẩm sinh - PT DOTY,Q24.4,Hẹp eo động mạch chủ,Q25.1,Hẹp phễu động mạch phổi,Q24.3,Hẹp van 2 lá - MITRAL,I05.0,Hẹp van 2 lá bẩm sinh,Q23.2,Hẹp van ba lá,I07.0,Hẹp van ĐMC bẩm sinh,Q23.0,Hẹp van động mạch chủ AROTIQUE,I35.0,Hẹp van động mạch phổi,I37.0,Hẹp van động mạch phổi bẩm sinh,Q22.1,Hở va ba lá,I07.1,Hở van 2 lá bẩm sinh,Q23.3,Hở van ĐMC bẩm sinh,Q23.1,Hở van động mạch chủ,I35.1,Hở van động mạch phổi bẩm sinh,Q22.2,Hở van hai lá,I34.0,Hội chứng Eissenmenger,Q21.8,Hội chứng kích thích sớm,I45.6,Hội chứng suy nút xoang,I49.5,Hội chứng thiểu sản thất trái,Q23.4,Huyết khối trong tim,I51.3,Kênh nhĩ thất - CAV,Q21.2,Không lỗ van 2 lá bẩm sinh,Q23.2,Không lỗ van 3 lá,Q22.4,Không lỗ van động mạch phổi,Q22.0,Không lỗ van động mạch phổi kèm thông liên thất - ASPO,Q21.3,Loạn nhịp thất do vòng vào lại - Hội chứng WPW,I47.0,Máy tạo nhịp tim,Z95.0,Mổ bắc cầu MV - PONTAGES,Z95.1,Ngoại tâm thu bộ nối,I49.2,Ngoại tâm thu nhĩ,I49.1,Ngoại tâm thu thất - PVC,I49.3,Ngưng tim,I46,Ngưng tim được cứu sống,I46.0,Nhiễm siêu vi không xác định,B09,Nhịp nhanh thất,I47.2,Nhịp nhanh trên thất,I47.1,Nhịp nhanh xoang,I47.2,Nhồi máu não,I63,Nhồi máu cơ tim cấp,I21,Nhồi máu cơ tim cũ,I25.2,Nhồi máu não,I63,Nối kết tĩnh mạch phổi bất thường bán phần,Q26.3,Nối kết tĩnh mạch phổi bất thường toàn phần,Q26.2,Nong và đặt stent,Z95.5,Phình xoang valsava (vỡ),Q25.4,Rối loạn lipid máu - RLLM,E78.4,Rối loạn nhịp không xác định,I49.9,Rối loạn nhịp tim ,I49.9,Rối loạn thần kinh tim,F45.3,Rung nhĩ và cuồng nhĩ,I48,Rung thất và cuồng thất,I49.0,Sốt DENGUE,A90,Suy động mạch vành mạn,I25,Suy giáp,E03,Suy tim sung huyết,I50.0,Tai biến mạch máu não,I64,TAKAYZASU,M31.4,Tâm thất độc nhất,Q20.4,Tăng áp phổi tiên phát,I27.0,Tăng huyết áp,I10,Tăng huyết áp do bệnh mạch máu thận,I15.0,Tăng huyết áp thứ phát,I15.8,Thân chung động mạch,Q20.0,Thất phải 2 đường ra,Q21.1,Thiểu sản động mạch chủ,Q25.4,Thông liên nhĩ - CIA,Q21.1,Thông liên thất - CIV,Q21.0,Thuyên tắc phổi,I26,Tim bên phải,Q24.0,Tồn tại tĩnh mạch chủ trên trái,Q26.1,Tràn dịch màng ngoài tim,I31.3,Tứ chứng Fallot ,Q21.3,Van ĐMC 2 mảnh,Q23.1,Van nhân tạo,Z95.2,Viêm cơ tim cấp,I40,Viêm dạ dày và tá tràng,K29,Viêm động mạch chủ - TAKAZASU,I79.1,Viêm họng cấp,J02,Viêm màng ngoài tim cấp,I30,Viêm màng ngoài tim co thắt mãn tính,I31.1,Viêm nội tâm mạc nhiễm trùng cấp và bán cấp,I33.0,Viêm phổi do virus không phân loại nơi khác,J12,Viêm tĩnh mạch và tắc tĩnh mạch,I80,Viêm xoang mạn,J32,Xuất huyết não,I61";
                    string[] list = dataType.Split(',');

                    for (int i = 0; i < list.Length; i += 2)
                    {
                        data.Add(new ObjectData() { Name = list[i], ID = list[i + 1] });
                    }

                    break;
                case StatusType.DungTuyen_TraiTuyen:
                    data = new List<ObjectData>()
                    {
                        new ObjectData(){Name="Đúng tuyến",ID="DT"},
                        new ObjectData(){Name="Trái tuyến",ID="TT"}

                    };
                    break;
                case StatusType.BoPhanBHYT_NT_NG:
                    data = new List<ObjectData>()
                    {
                        new ObjectData(){Name="Ngoại trú (NG)",ID="NG"},
                        new ObjectData(){Name="Nội trú (NT)",ID="NT"}

                    };
                    break;
            }

            InitStatusCombobox(control, data.ToList<dynamic>(), "Name", "ID", showSelectAll, isDropDownList, suggestMode, autoCompleteMode);
        }

        public static void InitStatusCombobox(ComboBox control, string customData, bool showSelectAll = true, bool isDropDownList = true, bool suggestMode = false)
        {
            string[] items = customData.Split(',');

            InitStatusCombobox(control, items.ToList(), showSelectAll, isDropDownList, suggestMode);
        }

        public static void InitStatusCombobox(ComboBox control, List<string> itemlist, bool showSelectAll = true, bool isDropDownList = true, bool suggestMode = false, AutoCompleteMode autoCompleteMode = AutoCompleteMode.SuggestAppend)
        {
            AutoCompleteStringCollection source = new AutoCompleteStringCollection();
            DataTable table = DataLib.initDataTable("StatusType[ Code, Name ]");
            if (showSelectAll)
            {
                itemlist.Insert(0, "%");
                itemlist.Insert(0, "Tất cả");
            }

            for (int i = 0; i < itemlist.Count; i += 2)
            {
                table.Rows.Add(new object[] { itemlist[i + 1], itemlist[i] });
                source.Add(itemlist[i]);
            }

            control.DropDownStyle = isDropDownList ? ComboBoxStyle.DropDownList : ComboBoxStyle.DropDown;

            control.DataSource = table;
            control.DisplayMember = "Name";
            control.ValueMember = "Code";

            if (!isDropDownList && suggestMode)
            {
                control.AutoCompleteSource = AutoCompleteSource.ListItems;
                control.AutoCompleteMode = autoCompleteMode;
                control.AutoCompleteCustomSource = source;
            }
        }

        public static void InitStatusCombobox(ComboBox control, List<dynamic> datasource, string displayMember, string valueMember, bool showSelectAll = true, bool isDropDownList = true, bool suggestMode = false, AutoCompleteMode autoCompleteMode = AutoCompleteMode.SuggestAppend)
        {
            AutoCompleteStringCollection source = new AutoCompleteStringCollection();


            if (showSelectAll && datasource.Count > 0)
            {
                Type type = datasource[0].GetType();
                var selectAllItem = Activator.CreateInstance(type, null);

                foreach (var item in type.GetProperties())
                {
                    if (item.Name == displayMember)
                    {
                        item.SetValue(selectAllItem, "Tất cả", null);
                    }
                    else if (item.Name == valueMember)
                    {
                        if (GetPropertyTypeName(item) == "String")
                            item.SetValue(selectAllItem, "%", null);
                        else
                            item.SetValue(selectAllItem, 0, null);
                    }
                }

                datasource.Insert(0, selectAllItem);
            }

            control.DropDownStyle = isDropDownList ? ComboBoxStyle.DropDownList : ComboBoxStyle.DropDown;

            
            control.DisplayMember = displayMember;
            control.ValueMember = valueMember;
            control.DataSource = datasource;

            if (!isDropDownList && suggestMode)
            {
                control.AutoCompleteSource = AutoCompleteSource.ListItems;
                control.AutoCompleteMode = autoCompleteMode;
                control.AutoCompleteCustomSource = source;
            }
        }

        public static void WriteLog(object ex, string explain)
        {
            FileLib.writeLog(FileLib.getRandomName("Log-" + MainFormModel.GetServerDateTime().ToString("yyyy-MM-dd"), null, "txt"), ex, explain);
        }

        public enum DBErrorType
        {
            None = -1,
            RecordOutOfDate = 0,
            AddExistedRecord = 1,
            RecordNotExisted = 2,
            UnknownError = 3,
            AccountIsNotExisted = 4,
            PasswordIsNotCorrect = 5,
            AccountIsLocked = 6,
            DataLengthTruncated = 7
        }

        public enum FormMessageType
        {
            UpdateSuccess = 0,
            UpdateFail = 1,
            AddSuccessConfirm = 2,
            AddFail = 3,
            DisposeSuccess = 4,
            DisposeFail = 5,
            ConfirmDispose = 6,
            ConfirmCancel = 7,
            ConfirmAccept = 8,
            CloseFormNotReady = 9,
            RecordNotFound = 10,
            ReportNotFound = 11,
            LoginFail = 12,
            NotAllơwDisposeRelateReportData = 13,
            ConfirmDisposeNoReason = 14,
            ConfirmRequireInput = 15,
        }


        public static ReturnSet FormMessage(FormMessageType type, string name)
        {
            return FormMessage(type, new string[] { name }, null, DBErrorType.None);
        }

        public static ReturnSet FormMessage(FormMessageType type, string[] name)
        {
            return FormMessage(type, name, null, DBErrorType.None);
        }

        public static ReturnSet FormMessage(FormMessageType type, string name, string detailMessage)
        {
            return FormMessage(type, new string[] { name }, detailMessage, DBErrorType.None);
        }

        public static ReturnSet FormMessage(FormMessageType type, string[] name, string detailMessage)
        {
            return FormMessage(type, name, detailMessage, DBErrorType.None);
        }

        public static ReturnSet FormMessage(FormMessageType type, string name, string detailMessage, DBErrorType errorType)
        {
            return FormMessage(type, new string[] { name }, detailMessage, errorType);
        }

        public static ReturnSet FormMessage(FormMessageType type, string[] name, string detailMessage, DBErrorType errorType)
        {
            string displayName = null; //do not display name if null

            if (name == null)
            {
                displayName = null;
            }
            else if (name.Length == 1 && StringLib.isValid(name[0]))//display object name only
            {
                displayName = name[0].Trim();
            }
            else if (name.Length >= 2) //display object name and record info
            {
                displayName = string.Format("{0} [{1}]", name[0].Trim(), name[1].Trim());
            }

            PropertyInfo[] prop = MainFormModel.Instance.CustomLanguageSet.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
            string typename = type.ToString();
            var rs = prop.Where(x => x.Name.Replace("FRM_", "") == typename);
            if (rs.Count() == 0) return new ReturnSet(false);
            string message = rs.First().GetValue(MainFormModel.Instance.CustomLanguageSet, null).ToString();



            if (!StringLib.isValid(displayName))//do not display name if null
            {
                message = message.Replace("{0} ", "");
            }
            else
            {
                message = string.Format(message, displayName);
            }

            //add detail message if available
            if (StringLib.isValid(detailMessage))
            {
                message += "\r\n" + detailMessage;
            }

            //add database error message if available
            if (errorType != DBErrorType.None)
            {
                typename = errorType.ToString();
                rs = prop.Where(x => x.Name.Replace("DB_", "") == typename);
                if (rs.Count() > 0)
                {
                    if (!StringLib.isValid(displayName))//do not display name if null
                    {
                        message += "\r\n\r\nLỗi: " + rs.First().GetValue(MainFormModel.Instance.CustomLanguageSet, null).ToString().Replace("{0} ", "");
                    }
                    else
                    {
                        message += "\r\n\r\nLỗi: " + string.Format(rs.First().GetValue(MainFormModel.Instance.CustomLanguageSet, null).ToString(), displayName);
                    }
                }
            }

            if (type.ToString().ToLower().Contains("confirm"))
            {
                if (type == FormMessageType.ConfirmDispose || type == FormMessageType.ConfirmRequireInput)
                {
                    InputDialog form = new InputDialog(MainFormModel.Instance.CustomLanguageSet.MessageBoxTitle, MainFormModel.Instance.CustomLanguageSet.InputFieldTitle, message);
                    form.ShowDialog();
                    return new ReturnSet(form.DialogResult == DialogResult.OK, form.DialogContent, form.DialogContent);
                }
                return new ReturnSet(FormLib.confirm(message, MainFormModel.Instance.CustomLanguageSet.MessageBoxTitle));
            }
            else
            {
                FormLib.alert(message, MainFormModel.Instance.CustomLanguageSet.MessageBoxTitle);
            }

            return new ReturnSet(true);
        }

        public static string BoolToTRUEString(bool value)
        {
            return value ? "X" : "";
        }

        public static string BoolToFALSEString(bool value)
        {
            return value ? "" : "X";
        }

        public static void EnableMultiControl(Control[] controlsToEnable, Control[] controlsToDisable = null)
        {
            if (controlsToEnable != null)
                foreach (var item in controlsToEnable)
                {
                    if (item.GetType().Name == typeof(DataGridView).Name)
                    {
                        ((DataGridView)item).AllowUserToDeleteRows = true;
                    }
                    else
                        item.Enabled = true;
                }

            if (controlsToDisable != null)
                foreach (var item in controlsToDisable)
                {
                    if (item.GetType().Name == typeof(DataGridView).Name)
                    {
                        ((DataGridView)item).AllowUserToDeleteRows = false;
                    }
                    else
                        item.Enabled = false;
                }
        }

        public static void Fill_InfoDataToControl(object item, System.Windows.Forms.Control.ControlCollection controlList, bool includeVisibleControl = false)
        {
            List<Control> list = new List<Control>();
            list.AddRange(controlList.OfType<Control>());
            Fill_InfoDataToControl(item, list, includeVisibleControl);
        }
        public static void Fill_InfoDataToControl(object item, List<Control> controlList, bool includeVisibleControl = false)
        {
            PropertyInfo[] properties = item.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
            foreach (var prop in properties)
            {
                foreach (Control control in controlList)
                {
                    if ( (includeVisibleControl || control.Visible) && control.Name == prop.Name)
                    {
                        switch (control.GetType().Name)
                        {
                            case "ExDateTimePicker":
                                try { ((ExDateTimePicker)control).Values = prop.GetValue(item, null) != null ? (DateTime)prop.GetValue(item, null) : DateTimeLib.NullDateTime;}catch { }
                                break;
                            case "DateTimePicker":
                                try { ((DateTimePicker)control).Value = prop.GetValue(item, null) != null ? (DateTime)prop.GetValue(item, null) : DateTimeLib.NullDateTime; }
                                catch { }
                                break;
                            case "ExComboBox":
                                try {
                                    ((ExComboBox)control).SelectedValue = prop.GetValue(item, null);
                                }catch { }
                                break;
                            case "ComboBox":
                                try {
                                    ((ComboBox)control).SelectedValue = prop.GetValue(item, null);
                                }catch { }
                                break;
                            case "NumericUpDown":
                                try { ((NumericUpDown)control).Value = (decimal)NumberLib.getDouble(prop.GetValue(item, null));}catch { }
                                break;
                            case "TextBox":
                                try { control.Text = prop.GetValue(item, null) != null ? prop.GetValue(item, null).ToString() : ""; }
                                catch { }
                                break;
                            case "CheckBox":
                                try {
                                    switch (GetPropertyTypeName(prop))
                                    {
                                        case "Double":
                                        case "Int32":
                                        case "String":
                                            int value = NumberLib.getInt(prop.GetValue(item, null));
                                            ((CheckBox)control).CheckState = value == 1 ? CheckState.Checked : value == 0 ? CheckState.Unchecked : CheckState.Indeterminate;
                                            break;                                         
                                        case "Boolean":
                                            ((CheckBox)control).Checked = (bool)prop.GetValue(item, null);
                                            break;
                                        default: FormLib.alert("Type:" + GetPropertyTypeName(prop) + " for:" + control.GetType().Name); break;
                                    }
                                }
                                catch {}
                                break;
                            case "RadioButton":
                                try
                                {
                                    switch (GetPropertyTypeName(prop))
                                    {
                                        case "Double":
                                        case "Int32":
                                        case "String":
                                            int value = NumberLib.getInt(prop.GetValue(item, null));
                                            ((RadioButton)control).Checked = value == 1 ? true : false;
                                            break;
                                        case "Boolean":
                                            ((RadioButton)control).Checked = (bool)prop.GetValue(item, null);
                                            break;
                                        default: FormLib.alert("Type:" + GetPropertyTypeName(prop) + " for:" + control.GetType().Name); break;
                                    }
                                }
                                catch { }
                                break;
                            default:
                                FormLib.alert("Unknown action for control type:" + control.GetType().Name + " Name:" + control.Name);
                                break;
                        }
                    }
                }
            }
        }
        public static void Fill_InfoDataFromControl(object item, System.Windows.Forms.Control.ControlCollection controlList, bool includeVisibleControl = false)
        {
            List<Control> list = new List<Control>();
            list.AddRange(controlList.OfType<Control>());
            Fill_InfoDataFromControl(item, list, includeVisibleControl);
        }
        public static void Fill_InfoDataFromControl(object item, List<Control> controlList, bool includeVisibleControl = false)
        {
            PropertyInfo[] properties = item.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
            foreach (var prop in properties)
            {
                foreach (Control control in controlList)
                {
                    if ( (includeVisibleControl || control.Visible) && control.Name == prop.Name)
                    {
                        switch (control.GetType().Name)
                        {
                            case "ExDateTimePicker":
                                switch (GetPropertyTypeName(prop))
                                {
                                    case "DateTime": prop.SetValue(item, ((ExDateTimePicker)control).Values, null); break;
                                    case "String": prop.SetValue(item, ((ExDateTimePicker)control).Values.ToDMYString(), null); break;
                                    default: FormLib.alert("Type:" + GetPropertyTypeName(prop) + " for:" + control.GetType().Name); break;

                                }
                                break;
                            case "DateTimePicker":
                                switch (GetPropertyTypeName(prop))
                                {
                                    case "DateTime": prop.SetValue(item, ((DateTimePicker)control).Value, null); break;
                                    case "String": prop.SetValue(item, ((DateTimePicker)control).Value.ToDMYString(), null); break;
                                    default: FormLib.alert("Type:" + GetPropertyTypeName(prop) + " for:" + control.GetType().Name); break;

                                }
                                break;
                            case "ComboBox":
                                switch (GetPropertyTypeName(prop))
                                {
                                    case "Double": prop.SetValue(item, NumberLib.getDouble(((ComboBox)control).SelectedValue), null); break;
                                    case "Int32": prop.SetValue(item, NumberLib.getInt(((ComboBox)control).SelectedValue), null); break;
                                    case "String": prop.SetValue(item, ((ComboBox)control).SelectedValue.ToString(), null); break;
                                    case "Boolean": prop.SetValue(item, ((ComboBox)control).SelectedValue, null); break;
                                    default: FormLib.alert("Type:" + GetPropertyTypeName(prop) + " for:" + control.GetType().Name); break;
                                }
                                break;
                            case "ExComboBox":
                                switch (GetPropertyTypeName(prop))
                                {
                                    case "Double": prop.SetValue(item, NumberLib.getDouble(((ExComboBox)control).SelectedValue), null); break;
                                    case "Int32": prop.SetValue(item, NumberLib.getInt(((ExComboBox)control).SelectedValue), null); break;
                                    case "String": prop.SetValue(item, ((ExComboBox)control).SelectedValue.ToString(), null); break;
                                    case "Boolean": prop.SetValue(item, ((ExComboBox)control).SelectedValue, null); break;
                                    default: FormLib.alert("Type:" + GetPropertyTypeName(prop) + " for:" + control.GetType().Name); break;
                                }
                                break;
                            case "TextBox":
                                switch (GetPropertyTypeName(prop))
                                {
                                    case "Double": prop.SetValue(item, NumberLib.getDouble(control.Text), null); break;
                                    case "Int32": prop.SetValue(item, NumberLib.getInt(control.Text), null); break;
                                    case "String": prop.SetValue(item, control.Text, null); break;
                                    default: 
                                        FormLib.alert("Type:" + GetPropertyTypeName(prop) + " for:" + control.GetType().Name); 
                                        break;
                                }
                                break;
                            case "NumericUpDown":
                                switch (GetPropertyTypeName(prop))
                                {
                                    case "Double": prop.SetValue(item, NumberLib.getDouble(((NumericUpDown)control).Value), null); break;
                                    case "Int32": prop.SetValue(item, NumberLib.getInt(((NumericUpDown)control).Value), null); break;
                                    case "String": prop.SetValue(item, ((NumericUpDown)control).Value.ToString(), null); break;
                                    default: FormLib.alert("Type:" + GetPropertyTypeName(prop) + " for:" + control.GetType().Name); break;
                                }
                                break;
                            case "CheckBox":
                                switch (GetPropertyTypeName(prop))
                                {
                                    case "Double": prop.SetValue(item, NumberLib.getDouble(((CheckBox)control).CheckState == CheckState.Checked ? 1 : ((CheckBox)control).CheckState == CheckState.Unchecked ? 0 : 2), null); break;
                                    case "Int32": prop.SetValue(item, NumberLib.getInt(((CheckBox)control).CheckState == CheckState.Checked ? 1 : ((CheckBox)control).CheckState == CheckState.Unchecked ? 0 : 2), null); break;
                                    case "String": prop.SetValue(item, ((CheckBox)control).CheckState == CheckState.Checked ? "1" : ((CheckBox)control).CheckState == CheckState.Unchecked ? "0" : "2", null); break;
                                    case "Boolean": prop.SetValue(item, ((CheckBox)control).Checked, null); break;
                                    default: FormLib.alert("Type:" + GetPropertyTypeName(prop) + " for:" + control.GetType().Name); break;
                                }
                                break;
                            case "RadioButton":
                                switch (GetPropertyTypeName(prop))
                                {
                                    case "Double": prop.SetValue(item, NumberLib.getDouble(((RadioButton)control).Checked ? 1 : 0), null); break;
                                    case "Int32": prop.SetValue(item, NumberLib.getInt(((RadioButton)control).Checked ? 1 : 0), null); break;
                                    case "String": prop.SetValue(item, ((RadioButton)control).Checked ? "1" : "0", null); break;
                                    case "Boolean": prop.SetValue(item, ((RadioButton)control).Checked, null); break;
                                    default: FormLib.alert("Type:" + GetPropertyTypeName(prop) + " for:" + control.GetType().Name); break;
                                }
                                break;
                            default:
                                FormLib.alert("Unknown action for control type:" + control.GetType().Name + " Name:" + control.Name);
                                break;
                        }
                    }
                }
            }
        }

        public static string GenerateClassPropertiesStructure(object myclass, bool includeSTT = false, bool isIncludeAllPropertyType = false, string className = "MyClass")
        {
            return GenerateClassPropertiesStructure(myclass.GetType(), includeSTT, isIncludeAllPropertyType, className);
        }

        public static string GenerateClassPropertiesStructure(Type myclass, bool includeSTT = false, bool isIncludeAllPropertyType = false, string className = "MyClass")
        {
            string result = "public class [CLASSNAME]\r\n{{\r\n{0}\r\n{1}}}";

            string listProperty = "";
            PropertyInfo[] properties = myclass.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);

            string contructor = "\tpublic [CLASSNAME](){{}}\r\n\r\n\tpublic [CLASSNAME]({0} item[STT]){{\r\n{1}\t}}\r\n\r\n\tpublic {0} To{0}(){{\r\n{2}\t}}";
            string func1 = "", func2 = "\t\tvar item = new "+myclass.Name+"();\r\n";
            
            foreach (var prop in properties)
            {
                if ( !isIncludeAllPropertyType && !"INT INT16 INT32 INT64 LONG BOOL BOOLEAN DOUBLE STRING DATETIME".Contains(GetPropertyTypeName(prop).ToUpper()) ) continue;
                listProperty += string.Format("\tpublic {0} {1} {{ get; set; }}\r\n", GetPropertyTypeName(prop), prop.Name);
                func1 += string.Format("\t\t{0} = item.{1} != null ? item.{2} : {3};\r\n", prop.Name, prop.Name, IsNullablePropertyType(prop) ? prop.Name + ".Value" : prop.Name, GetPropertyTypeNameDefaultValue(prop));
                func2 += string.Format("\t\titem.{0} = {0};\r\n", prop.Name);
            }
            func2 += "\t\treturn item;\r\n";

            if (includeSTT)
            {
                listProperty += string.Format("\tpublic {0} {1} {{ get; set; }}\r\n", typeof(Int32).Name, "STT");
                func1 += "\t\tSTT = _STT;\r\n";
                contructor = contructor.Replace("[STT]", ", int _STT");
            }
            else
            {
                contructor = contructor.Replace("[STT]", "");
            }

            contructor = string.Format(contructor, myclass.Name, func1, func2);
            result = string.Format(result, contructor, listProperty);
            result = result.Replace("[CLASSNAME]", className);
            return result;
        }

        public static string GenerateDataGridViewColumnsFromObject(Type myclass, bool isIncludeAllPropertyType = false)
        {
            string result = "";
            PropertyInfo[] properties = myclass.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);

            Hashtable columnNames = new Hashtable();
            columnNames.Add("NguoiCapNhat",     "Người cập nhật");
            columnNames.Add("NgayCapNhat",      "Ngày cập nhật");
            columnNames.Add("NguoiTao",         "Người lập");
            columnNames.Add("NgayTao",          "Ngày lập");
            columnNames.Add("NguoiLapCT",       "Người lập");
            columnNames.Add("NgayLapCT",        "Ngày lập");
            columnNames.Add("TinhTrang",        "Tình trạng");
            columnNames.Add("SoChungTu",        "Số chứng từ");
            columnNames.Add("NgayChungTu",      "Ngày chứng từ");
            columnNames.Add("LyDoHuy",          "Lý do hủy");

            Form form = new Form();
            form.Size = new Size(800, 600);
            form.StartPosition = FormStartPosition.CenterScreen;

            DataGridView grid = new DataGridView();
            grid.Columns.AddRange(new DataGridViewColumn[] { 
                DataLib.GenColumn("Select", "select", DataLib.GenColumnType.CheckBox).SetReadOnly(false),
                DataLib.GenColumn("Property", "property").SetReadOnly(true),
                DataLib.GenColumn("Header", "header").SetReadOnly(false),
                DataLib.GenColumn("Type", "type", DataLib.GenColumnType.ComboBox).SetComboBoxItems(Enum.GetNames( typeof(DataLib.GenColumnType))).SetReadOnly(false),
                DataLib.GenColumn("Visible", "visible", DataLib.GenColumnType.CheckBox).SetReadOnly(false),
                DataLib.GenColumn("Align", "align", DataLib.GenColumnType.ComboBox).SetReadOnly(false).SetComboBoxItems(new string[]{"Left","Right","Center"}),
                DataLib.GenColumn("Format", "format").SetReadOnly(false).SetAlign(DataGridViewContentAlignment.MiddleCenter),
            });
            
            grid.Dock = DockStyle.Fill;            
            grid.DataError += delegate(object sender, DataGridViewDataErrorEventArgs e){e.Cancel = true;};
            form.Controls.Add(grid);
            
            foreach (var prop in properties)
            {
                if (!isIncludeAllPropertyType && !"INT INT16 INT32 INT64 LONG BOOL BOOLEAN DOUBLE STRING DATETIME".Contains(GetPropertyTypeName(prop).ToUpper())) continue;
                grid.Rows.Add(new object[] { 
                    true,
                    prop.Name, columnNames.ContainsKey(prop.Name) ? columnNames[prop.Name] : prop.Name, 
                    GetPropertyTypeName(prop).ToUpper() == "DATETIME" ? "DateTime" : "Text", 
                    true, 
                    GetPropertyTypeName(prop).ToUpper() == "DATETIME" ? "Center": GetPropertyTypeName(prop).ToUpper() == "DOUBLE" ? "Right" : "Left", 
                    GetPropertyTypeName(prop).ToUpper() == "DATETIME" ? "dd/MM/yyyy" : GetPropertyTypeName(prop).ToUpper() == "DOUBLE" ? "#,0" : ""
                });
            }

            form.ShowDialog();

            foreach (DataGridViewRow item in grid.Rows)
            {
                if (item.Cells["select"].Value == null || ((bool)item.Cells["select"].Value) == false) continue;
                result += string.Format(
                    "DataLib.GenColumn(\"{1}\", \"{0}\"{2}){3}{4}{5},\r\n", 
                    item.Cells["property"].Value, 
                    item.Cells["header"].Value,
                    item.Cells["type"].Value.ToString() == "Text" ? "" : ", DataLib.GenColumnType." + item.Cells["type"].Value,
                    item.Cells["visible"].Value == null || ((bool)item.Cells["visible"].Value) == false ? ".SetVisible(false)" : "",
                    item.Cells["align"].Value.ToString() == "Left" ? "" : ".SetAlign(DataGridViewContentAlignment.Middle"+item.Cells["align"].Value+")",
                    item.Cells["format"].Value.ToString() == "" ? "" : ".SetFormat(\""+item.Cells["format"].Value+"\")"
                );
            }

            return result;
        }

        
        

        public static string GenerateReportParamFromRDLC(string RDLCfile)
        {
            ReportViewer reportViewer1 = new ReportViewer();

            reportViewer1.ProcessingMode = Microsoft.Reporting.WinForms.ProcessingMode.Local;
            reportViewer1.LocalReport.ReportPath = RDLCfile;

            string content1 = "var a = new CLASS()\r\n{";
            string content = "";

            foreach (var item in reportViewer1.LocalReport.GetParameters())
            {
                switch (item.DataType.ToString())
                {
                    case "String":
                        content += string.Format("public string {0} ", item.Name) + "{ get; set; }\r\n";
                        content1 += string.Format("\t{0} = \"\",\r\n", item.Name);
                        break;
                    case "Float":
                        content += string.Format("public double {0} ", item.Name) + "{ get; set; }\r\n";
                        content1 += string.Format("\t{0} = 0,\r\n", item.Name);
                        break;
                    default:
                        content += string.Format("public {1} {0} ", item.Name, item.DataType.ToString()) + "{ get; set; }\r\n";
                        content1 += string.Format("\t{0} = \"\",\r\n", item.Name);
                        break;
                }
            }
            content1 += "}";

            return content +"\r\n"+ content1;
        }

        public static string GenerateEFDataMgrPanel(object myclass)
        {
            return GenerateEFDataMgrPanel(myclass.GetType());
        }

        public static string GenerateEFDataMgrPanel(Type myclass)
        {
            string content = "var entity = DBManager.InitEntity();\r\n";
            content += "EFDataMgrPanel panel = new EFDataMgrPanel();\r\n";
            content += "panel.InitForm(entity, entity.DM_DichVu, MainForm.Instance.ItemPerPage, _ORDER_BY_FIELD_, new List<SearchItem>() {\r\n";

            PropertyInfo[] properties = myclass.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
            foreach (var prop in properties)
            {
                if (!"INT INT16 INT32 INT64 LONG BOOL BOOLEAN DOUBLE STRING DATETIME".Contains(GetPropertyTypeName(prop).ToUpper())) continue;

                if (prop.Name.ToUpper().Contains("_ID"))
                {
                    content += string.Format("\tnew SearchItem(DataLib.GenColumn(\"{0}\", \"{0}\", DataLib.GenColumnType.ComboBox).SetComboBoxDataSource(data, \"\", \"\")),\r\n", prop.Name);
                }
                else
                {

                    switch (GetPropertyTypeName(prop))
                    {
                        case "DateTime":
                            content += string.Format("\tnew SearchItem(DataLib.GenColumn(\"{0}\", \"{0}\", DataLib.GenColumnType.DateTime).SetFormat(\"dd/MM/yyyy\")),\r\n", prop.Name);
                            break;
                        case "Double":
                            content += string.Format("\tnew SearchItem(DataLib.GenColumn(\"{0}\", \"{0}\").SetFormat(\"#,0\").SetAlign(DataGridViewContentAlignment.MiddleRight)),\r\n", prop.Name);
                            break;
                        case "Int32":
                            content += string.Format("\tnew SearchItem(DataLib.GenColumn(\"{0}\", \"{0}\").SetFormat(\"#,0\").SetAlign(DataGridViewContentAlignment.MiddleCenter)),\r\n", prop.Name);
                            break;
                        case "Boolean":
                            content += string.Format("\tnew SearchItem(DataLib.GenColumn(\"{0}\", \"{0}\", DataLib.GenColumnType.CheckBox)),\r\n", prop.Name);
                            break;
                        default:
                        case "String":

                            content += string.Format("\tnew SearchItem(DataLib.GenColumn(\"{0}\", \"{0}\")),\r\n", prop.Name);
                            break;
                    }
                }
                
            }

                
            content += "});\r\n";
            return content;
        }

        public static bool IsNullablePropertyType(PropertyInfo pro)
        {
            if (pro.PropertyType.Name.ToLower().Contains("null"))
                return true;

            return false;
        }

        public static string GetPropertyTypeName(PropertyInfo pro)
        {
            if (!pro.PropertyType.Name.ToLower().Contains("null"))
                return pro.PropertyType.Name;

            return pro.PropertyType.GetProperty("Value").PropertyType.Name;
        }

        private static object GetPropertyTypeNameDefaultValue(PropertyInfo pro)
        {
            switch (GetPropertyTypeName(pro))
            {
                case "String": return "\"\"";
                case "Boolean": return "false";
                case "DateTime": return "DateTimeLib.NullDateTime";
                default:
                    return "0";
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="list"></param>
        /// <param name="container"></param>
        public static void InitExceptEnterTabEvent(List<Control> list, Form container)
        {
            foreach (var item in list)
            {
                item.Enter += delegate { container.Tag = false; };
                item.Leave += delegate { container.Tag = true; };
            }
        }

        /// <summary>
        /// Tim tat ca cac textbox co multiline la true, add event de khi nhan Enter ko nhan Tab nua
        /// </summary>
        /// <param name="container"></param>
        public static void InitMultiLineTextBoxAuto(Form container)
        {
            List<Control> items = new List<Control>();
            foreach (var item in FormLib.getChildControlList(container))
            {
                if (FormLib.getControlType(item) == ControlType.TextBox && ((TextBox)item).Multiline == true)
                {
                    items.Add(item);
                    ((TextBox)item).ScrollBars = ScrollBars.Both;
                    item.Enter += delegate { container.Tag = false; };
                    item.Leave += delegate { container.Tag = true; };
                }
            }
        }

        public static void InitMultiLineTextBox(List<TextBox> list, Form container)
        {
            foreach (var item in list)
            {
                item.ScrollBars = ScrollBars.Both;
                item.Multiline = true;
                item.Enter += delegate { container.Tag = false; };
                item.Leave += delegate { container.Tag = true; };
            }
        }


        public enum SoCTType { Prefix_yy_Counter, Prefix_yyMM_Counter }
        public static string ValidateSoCT(string soct, string prefix, SoCTType type = SoCTType.Prefix_yyMM_Counter, int counterLength = 5, char spliterString = '-')
        {
            soct = soct.ToUpper().Replace(prefix.ToUpper(), "");
            string sotn = StringLib.filterStr(soct.Trim(), "0123456789" + spliterString);
            while (sotn.StartsWith(spliterString.ToString())) sotn = sotn.Substring(1);

            string counterFormat = "";
            for (int i = 0; i < counterLength; i++) counterFormat += "0";
            string dateFormat = type.ToString().Split('_')[1];
            string format = "{0}{3}{1:" + dateFormat + "}{3}{2:" + counterFormat + "}";

            DateTime date = MainFormModel.GetServerDateTime();
            int counter = NumberLib.getInt(sotn);

            if (sotn.Contains(spliterString))
            {
                string datestr = sotn.Split(spliterString)[0];

                if (dateFormat == "yy")
                {
                    date = new DateTime(NumberLib.getInt("20" + (datestr.Length > 2 ? datestr.Substring(datestr.Length - 2, 2) : datestr)), date.Month, date.Day);
                }
                else if (dateFormat == "yyMM")
                {
                    int year = NumberLib.getInt("20" + (datestr.Length > 2 ? datestr.Substring(0, 2) : datestr));
                    int month = datestr.Length <= 2 ? date.Month : NumberLib.getInt(datestr.Substring(2));
                    DateTime newDate = date;
                    newDate = newDate.AddDays(-(date.Day));

                    int day = newDate.Day;
                    if (month == date.Month)
                    {
                        day = date.Day;
                    }
                    else
                    {
                        day = DateTime.DaysInMonth(year, month);
                    }

                    date = new DateTime(year, month > 12 ? 12 : month < 1 ? 1 : month, day);
                }

                counter = NumberLib.getInt(sotn.Split(spliterString)[1]);
            }

            return string.Format(format, prefix, date, counter, spliterString);
        } 
    }
}
